package com.kobeliu.filter;

import com.google.gson.Gson;
import com.kobeliu.base.BaseInfoProperties;
import com.kobeliu.result.GraceJSONResult;
import com.kobeliu.result.ResponseStatusEnum;
import com.kobeliu.utils.IPUtil;
import com.kobeliu.utils.JwtUtils;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
@Slf4j
public class IpFilterJwt extends BaseInfoProperties implements GlobalFilter, Ordered{

    @Autowired
    private ExcludeUrlPathProperties excludeUrlPathProperties;

    //路径匹配工具类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Value("${blackIP.continueCounts}")
    private Integer continueCounts;
    @Value("${blackIP.timeInterval}")
    private Integer timeInterval;
    @Value("${blackIP.limitTimes}")
    private Integer limitTimes;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //一键注册，登出，获取验证码不需要验证 token直接放行

        //1.获取需要监控的url集合
        List<String> urls = excludeUrlPathProperties.getIpLimitUrls();

        //2.获取当前请求的路由
        String url = exchange.getRequest().getURI().getPath();

        //3.做校验并且排除
        if(urls !=null && !urls.isEmpty()){
            for(String limitUrl:urls){
                if(antPathMatcher.matchStart(limitUrl,url)){
                    //若匹配到直接放行
                    doLimit(exchange,chain);
                }
            }
        }

        //默认放行
        return chain.filter(exchange);
    }

    private Mono<Void> doLimit(ServerWebExchange exchange, GatewayFilterChain chain) {
        //3.获取ip
        String ip = IPUtil.getIP(exchange.getRequest());

        final String gatewayIpKey = "GATEWAY_IP:"+ip;
        final String blackIpKey = "BLACK_IP:"+ip;

        //在小黑屋中的剩余时间
        long ttl = redis.ttl(blackIpKey);
        if(ttl>0){
            //代表在小黑屋中，直接拒绝
            return renderErrorFilter(exchange,ResponseStatusEnum.SYSTEM_ERROR);
        }
        //代表不在小黑屋中
        //去查在间隔时间中ip访问的次数
        //获得ip的访问累加次数
        long requestCount = redis.increment(gatewayIpKey, 1);

        if(requestCount==1){
            //代表是第一次进来
            //设定定时时间
            redis.expire(gatewayIpKey,timeInterval);
        }
        if(requestCount>=continueCounts){
            //若是count》=规定的次数，则需要做限制
            redis.set(blackIpKey+":"+ip,blackIpKey,limitTimes);
            //拒绝该请求
            //代表在小黑屋中，直接拒绝
            return renderErrorFilter(exchange,ResponseStatusEnum.SYSTEM_ERROR);
        }
        return chain.filter(exchange);
    }


    public Mono<Void> renderErrorFilter(ServerWebExchange exchange, ResponseStatusEnum statusEnum) {

        //1.获取response、
        ServerHttpResponse response = exchange.getResponse();
        //2.构建JsonResult
        GraceJSONResult graceJSONResult = GraceJSONResult.exception(statusEnum);
        //3.修改response的code为500
        response.setStatusCode(HttpStatus.BAD_GATEWAY);
        //4.设定header类型
        if(!response.getHeaders().containsKey("Content-Type")){
            response.getHeaders().add("Content-Type", MimeTypeUtils.APPLICATION_JSON_VALUE);
        }

        //5.转换Json且向response中写入数据
        String resultJson = new Gson().toJson(graceJSONResult);
        DataBuffer dataBuffer = response.bufferFactory().wrap(resultJson.getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Mono.just(dataBuffer));


    }


    //过滤器的顺序，数字越小优先级越大
    @Override
    public int getOrder() {
        return 0;
    }
}
